package ar.com.spsolutions.splibrary.book;

import java.util.HashSet;
import java.util.Set;

import org.joda.time.DateTime;

import ar.com.spsolutions.splibrary.book.exceptions.ReservationException;
import ar.com.spsolutions.splibrary.entity.Entity;
import ar.com.spsolutions.splibrary.notifiers.INotifier;
import ar.com.spsolutions.splibrary.user.User;
import ar.com.spsolutions.splibrary.utils.DateUtil;

public class Reserve extends Entity {
	private static final long serialVersionUID = -116702045527397020L;

	private Book book;

	private User customer;

	private Set<User> observers = new HashSet<User>();

	private DateTime due;

	private INotifier notifier;

	public Reserve(final INotifier aNotifier) {
		super();
		this.notifier = aNotifier;
	}

	public void setNotifier(final INotifier notifier) {
		this.notifier = notifier;
	}

	public Reserve() {
		super();
	}

	public void addCustomer(final User aCustomer) {

		if (aCustomer.hasTheBookRented(this.getBook())) {
			throw new ReservationException(
					String.format(
							"El usuario %s no puede reservar el libro porque ya tiene una copia del mismo",
							aCustomer.getName()));
		}
		if (this.getCustomer() == null) {
			this.setCustomer(aCustomer);
			this.notifyReserveAccepted();
		} else {
			this.getObservers().add(aCustomer);
			this.notifyReserveObserverAccepted();
		}
	}

	private INotifier getNotifier() {
		return this.notifier;
	}

	private void notifyReserveObserverAccepted() {
		this.getNotifier().setRecipient(this.getCustomer());
		this.getNotifier().setSubject("Confirmacion de reserva");
		this.getNotifier()
				.setMessage(
						String.format(
								"Estimado %s,\n\t"
										+ "Le informamos que la reserva pasiva del libro %s a sido aceptada y se le notificara por este mismo medio cuando se encuentre disponible una copia del mismo.\n"
										+ "Advertencia: Junto a usted se le notificara a otros usuarios.",
								this.getCustomer().getName(), this.getBook()
										.getTitle()));
		this.getNotifier().sendNotification();
	}

	private void notifyReserveAccepted() {
		this.getNotifier().setRecipient(this.getCustomer());
		this.getNotifier().setSubject("Confirmacion de reserva");
		this.getNotifier()
				.setMessage(
						String.format(
								"Estimado %s,\n\t"
										+ "Le informamos que la reserva del libro %s a sido aceptada y se le notificara por este mismo medio cuando se encuentre disponible una copia del mismo.\n"
										+ "Advertencia: La reserva caducara 24HS habiles luego de la devolucion de la notificacion.",
								this.getCustomer().getName(), this.getBook()
										.getTitle()));
		this.getNotifier().sendNotification();
	}

	// ---accessors---

	public Book getBook() {
		return this.book;
	}

	public void setBook(final Book book) {
		this.book = book;
	}

	public User getCustomer() {
		return this.customer;
	}

	public void setCustomer(final User customer) {
		this.customer = customer;
	}

	public Set<User> getObservers() {
		return this.observers;
	}

	public void setObservers(final Set<User> observers) {
		this.observers = observers;
	}

	public DateTime getDue() {
		return this.due;
	}

	public void setDue(final DateTime due) {
		this.due = due;
	}

	public void notifyAvailableCopy() {
		this.getNotifier().setRecipient(this.getCustomer());
		this.getNotifier().setSubject("Notificacion de reserva");
		this.getNotifier()
				.setMessage(
						String.format(
								"Estimado %s,\n\t"
										+ "Le informamos que el libro %s ah sido devuelto y por lo tanto tiene hasta el %s disponible una copia del mismo.\n",
								this.getCustomer().getName(), this.getBook()
										.getTitle(), DateUtil.format(this
										.calculateReserveTime())));
		this.getNotifier().sendNotification();
	}

	private DateTime calculateReserveTime() {
		final DateTime dateTime = new DateTime().plusDays(1);
		return DateUtil.toDateTime(DateUtil.getLaboralDate(dateTime));
	}

	public void addBook(final Book aBook) {
		if (this.getBook() == null) {
			this.setBook(aBook);
		}
	}

}
